// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
#pragma once
#include "Common\DirectXHelper.h"

Microsoft::WRL::ComPtr<ID2D1Bitmap1> LoadBitmapFromStream(
    ID2D1DeviceContext* d2dContext,
    IWICImagingFactory2 *pIWICFactory,
    IStream* stream,
    UINT destinationWidth,
    UINT destinationHeight
    )
{
    Microsoft::WRL::ComPtr<IWICBitmapDecoder> decoder;
    Microsoft::WRL::ComPtr<IWICBitmapFrameDecode> source;
    Microsoft::WRL::ComPtr<IWICFormatConverter> converter;
    Microsoft::WRL::ComPtr<IWICBitmapScaler> scaler;

    DX::ThrowIfFailed(
        pIWICFactory->CreateDecoderFromStream(stream, nullptr, WICDecodeMetadataCacheOnLoad, &decoder)
        );

    // Create the initial frame.
    DX::ThrowIfFailed(
        decoder->GetFrame(0, &source)
        );

    // Convert the image format to 32bppPBGRA
    // (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
    DX::ThrowIfFailed(
        pIWICFactory->CreateFormatConverter(&converter)
        );

    // If a new width or height was specified, create an
    // IWICBitmapScaler and use it to resize the image.
    if (destinationWidth != 0 || destinationHeight != 0)
    {
        UINT originalWidth;
        UINT originalHeight;
        DX::ThrowIfFailed(
            source->GetSize(&originalWidth, &originalHeight)
            );
        if (destinationWidth == 0)
        {
            FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);
            destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));
        }
        else if (destinationHeight == 0)
        {
            FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);
            destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));
        }

        DX::ThrowIfFailed(
            pIWICFactory->CreateBitmapScaler(&scaler)
            );

        DX::ThrowIfFailed(
            scaler->Initialize(
            source.Get(),
            destinationWidth,
            destinationHeight,
            WICBitmapInterpolationModeCubic
            )
            );

        DX::ThrowIfFailed(
            converter->Initialize(
            scaler.Get(),
            GUID_WICPixelFormat32bppPBGRA,
            WICBitmapDitherTypeNone,
            nullptr,
            0.f,
            WICBitmapPaletteTypeMedianCut
            )
            );
    }
    else // Don't scale the image.
    {
        DX::ThrowIfFailed(
            converter->Initialize(
            source.Get(),
            GUID_WICPixelFormat32bppPBGRA,
            WICBitmapDitherTypeNone,
            nullptr,
            0.f,
            WICBitmapPaletteTypeMedianCut
            )
            );
    }

    D2D1_BITMAP_PROPERTIES1 bitmapProperties =
        D2D1::BitmapProperties1(
        D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
        D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED));

    // Create a Direct2D bitmap from the WIC bitmap.
    Microsoft::WRL::ComPtr<ID2D1Bitmap1> bitmap;
    DX::ThrowIfFailed(
        d2dContext->CreateBitmapFromWicBitmap(
        converter.Get(),
        &bitmapProperties,
        &bitmap
        )
        );

    return bitmap;
}

void SaveBitmapToStream(ID2D1Device1* device, IWICImagingFactory2* wicFactory2, ID2D1Bitmap1* bitmap, IStream* imageStream, const GUID& format)
{
    // Create and initialize WIC Bitmap Encoder. 
    Microsoft::WRL::ComPtr<IWICBitmapEncoder> wicBitmapEncoder;
    DX::ThrowIfFailed(
        wicFactory2->CreateEncoder(
        format,
        nullptr, // No preferred codec vendor. 
        &wicBitmapEncoder
        )
        );

    DX::ThrowIfFailed(
        wicBitmapEncoder->Initialize(
        imageStream,
        WICBitmapEncoderNoCache
        )
        );

    // Create and initialize WIC Frame Encoder. 
    Microsoft::WRL::ComPtr<IWICBitmapFrameEncode> wicFrameEncode;
    DX::ThrowIfFailed(
        wicBitmapEncoder->CreateNewFrame(
        &wicFrameEncode,
        nullptr     // No encoder options. 
        )
        );

    DX::ThrowIfFailed(
        wicFrameEncode->Initialize(nullptr)
        );

    // Create IWICImageEncoder.
    Microsoft::WRL::ComPtr<IWICImageEncoder> imageEncoder;
    DX::ThrowIfFailed(
        wicFactory2->CreateImageEncoder(
        device,
        &imageEncoder
        )
        );

    DX::ThrowIfFailed(
        imageEncoder->WriteFrame(
        bitmap,
        wicFrameEncode.Get(),
        nullptr     // Use default WICImageParameter options. 
        )
        );

    DX::ThrowIfFailed(
        wicFrameEncode->Commit()
        );

    DX::ThrowIfFailed(
        wicBitmapEncoder->Commit()
        );

    // Flush all memory buffers to the next-level storage object. 
    DX::ThrowIfFailed(
        imageStream->Commit(STGC_DEFAULT)
        );
}